<?php

/**
 * Класс шаблонизатора
 * @author Alexander NeonXP Kiryukhin
 * @copyright 2011 Alexander NeonXP Kiryukhin
 * @license GPLv2
 */
class tpl {
    private $arTemplates = array(), $arBlocks = array();
    protected static $instance;
    private function __clone() {

    }
    public static function getInstance() {
        return (self::$instance === null) ?
                self::$instance = new self() :
                self::$instance;
    }
    function __construct() {
        $arTemplates = glob('./templates/*.html');
        if ($arTemplates!=array()) {
            foreach ($arTemplates as $sTemplate) {
                $sName = str_replace('./templates/','',$sTemplate);
                $sName = str_replace('.html','',$sName);
                $this->arTemplates[$sName] = file_get_contents($sTemplate);
            }
        }
    }
    /**
     * Начальный парсинг шаблонов
     */
    function parseTemplates() {
        if ($this->arTemplates!=array()) {
            foreach ($this->arTemplates as $sName => $sTemplate) {
                $sTemplate = preg_replace("/\<var:(.+?)\>/i",'<?php print \$${1}; ?>',$sTemplate);
                $sTemplate = preg_replace("/\<for:(.+?):(.+?)\>/i",'<?php foreach (\$${1} as \$${2}) { ?>',$sTemplate);
                $sTemplate = preg_replace("/\<if:(.+?)\>/i",'<?php if (${1}) { ?>',$sTemplate);


                $sTemplate = preg_replace_callback('/\<typo\>(.+?)\<\/typo\>/is', array($this,'typo'), $sTemplate);


                $sTemplate = str_replace("<else>","<?php } else { ?>",$sTemplate);
                $sTemplate = str_replace("</for>","<?php } ?>",$sTemplate);
                $sTemplate = str_replace("</if>","<?php } ?>",$sTemplate);
                $this->arTemplates[$sName] = $sTemplate;
            }
            foreach ($this->arTemplates as $sName => $sTemplate) {
                $arMatches = array();
                preg_match_all("/\<template:(.+?)\>/i",$sTemplate,$arMatches);
                if (isset($arMatches[1]) && $arMatches[1]!=array())
                foreach($arMatches[1] as $sMatch) {
                    $sTemplate = str_replace("<template:$sMatch>",$this->arTemplates[$sMatch],$sTemplate);
                }

                $sTemplate = preg_replace_callback("/\<block:(.+?)\>(.+?)\<\/block\>/is", array($this,'addBlock'), $sTemplate);
                $sTemplate = preg_replace_callback("/\<include:(.+?)\>/is", array($this,'includeBlock'), $sTemplate);
                $this->arTemplates[$sName] = $sTemplate;
            }
        }
    }
    /**
     * Записываем в память новый блок
     * @param array $arMatches результат preg_replace_callback
     * @return string код внутри блока без внешних тегов блока
     */
    function addBlock($arMatches) {
        $this->arBlocks[$arMatches[1]] = $arMatches[2];
        return $arMatches[2];
    }
    /**
     * Вставляем блок из памяти в документ
     * @param array $arMatches результат preg_replace_callback
     * @return string код внутри блока без внешних тегов блока
     */
    function includeBlock($arMatches) {
        return $this->arBlocks[$arMatches[1]];
    }
    /**
     * Простенький типограф
     * @param array $arMatches результат preg_replace_callback
     * @return string текст, обработанный типографом
     */
    function typo($arMatches) {
        $sMatch = " ".$arMatches[1]." ";
        $sMatch = strip_tags($sMatch);
        $sMatch = str_replace(' "',' «',$sMatch);
        $sMatch = str_replace('" ','» ',$sMatch);
        $sMatch = str_replace('...','…',$sMatch);
        $sMatch = str_replace(' - ',' — ',$sMatch);
        $sMatch = str_replace('(c)','©',$sMatch);
        $sMatch = str_replace('(C)','©',$sMatch);
        return trim($sMatch);
    }
    /**
     * Рендерит указанный шаблон
     * @param string $sName имя шаблона, который будет обрабатываться.
     * @param array $arVaribles передаваемые в шаблон переменные в виде ассоциативного массива
     * @return string готовый к выдаче клиентскому браузеру код
     */
    function render($sName,$arVaribles=array()) {
        if (isset($this->arTemplates[$sName])) {
            $sTemplate = $this->arTemplates[$sName];
        } else {
            return false;
        }
        if ($arVaribles!=array()) {
            foreach ($arVaribles as $sKey=>$mixedValue) {
                $$sKey = $mixedValue;
            }
        }
        ob_start();
        eval("?>".$sTemplate."<?");
        return ob_get_clean();
    }
}

